#include "NetPcapSocket.h"
#include "common.h"
#include <iostream>

#ifdef __cplusplus
extern "C" {
#endif

#include "pcap.h"

#ifdef __cplusplus
}
#endif


NetPcapSocket::NetPcapSocket(const std::string& ifname)
{
    std::string _ifname = GetIfByMac(ifname);
    if ("" == _ifname) throw std::runtime_error("get if error");
    
    m_handler = open_if(_ifname);
    if (NULL == m_handler) throw std::runtime_error("open_if error : " + _ifname);
}

NetPcapSocket::~NetPcapSocket()
{
    if (m_handler)pcap_close(m_handler);
    m_handler = NULL;
}

int NetPcapSocket::SendData(DataCache& data, int timeout)
{
    if (pcap_sendpacket(m_handler, (unsigned char*)data(), data.size()) != 0)
    {
        LOGFMTD("Error sending the packet: %s", pcap_geterr(m_handler));
        return -1;
    }
    return 0;
}

int NetPcapSocket::RecvData(DataCache& data, int timeout)
{
    struct pcap_pkthdr* header;
    const u_char* pkt_data = NULL;
    int ret = 0;

    if ((ret = pcap_next_ex(m_handler, &header, &pkt_data)) < 0)
    {
        if (ret == 0)
            return 0;

        LOGFMTD("Error reading the packets: %s", pcap_geterr(m_handler));
        return -1;
    }
    if (NULL == pkt_data) return -1;

    memcpy(data(), pkt_data, header->len);
    data.set(header->len);

    return 0;
}

pcap_t* NetPcapSocket::open_if(const std::string& ifname)
{
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_if_t* alldevs = NULL, * cur = NULL;
    pcap_t* handler = NULL;
    std::string tempStr = "", _tempStr = "";

    if (pcap_findalldevs(&alldevs, errbuf) == -1)
    {
        LOGFMTD("pcap_findalldevs : %s ", ifname.c_str());
        return handler;
    }

    for (pcap_if_t* d = alldevs; d; d = d->next)
    {
#ifndef WIN32
        if (d->name != NULL && 0 == ifname.compare(d->name))
        {
            cur = d; break;
        }
#else
        LOGFMTD("mac : %s - %s , %s", d->description, d->name, ifname.c_str());
        if (std::string(d->name).find(ifname) != std::string::npos)
        {
            cur = d; break;
        }
#endif
    }
    if (NULL == cur)
    {
        LOGFMTE(
            "no corresponding device found : %s ", 
            ifname.c_str()
        );
        pcap_freealldevs(alldevs);
        return handler;
    }

    if (NULL == (handler = pcap_open_live(cur->name, 65536, 1, 1000, errbuf)))
    {
        LOGFMTE(
            "Unable to open the adapter. %s is not supported Pcap, %s",
            cur->name, errbuf
        );
    }

    pcap_freealldevs(alldevs);
    return  handler;
}